#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct pool {
    int size;
    void *pPool;
} Pool_t;

typedef struct msg{
    void *pMsg;
    struct msg *next;
} Msg_t;

typedef struct {
    char *name;
    int queueLength;
    int msgSize;
    int curLen;
    Pool_t msgPool;
    Pool_t listPool;
    Msg_t *msgListHead;
    Msg_t *msgListTail;
} Queue_t;

typedef Queue_t * QueueHandle_t;

QueueHandle_t createMsgQueue(const char *name, int queueLength, int msgSize){
    QueueHandle_t queueHandle = (QueueHandle_t)malloc(sizeof(Queue_t));
    if(!queueHandle){
        printf("queue handle create failed!\n");
        return NULL;
    }
    queueHandle->name = name;
    queueHandle->msgSize = msgSize;
    queueHandle->queueLength = queueLength;
    queueHandle->curLen = 0;
    queueHandle->msgPool.pPool = malloc(queueLength * msgSize + queueLength);
    if(!queueHandle->msgPool.pPool){
        printf("queue message pool create failed!\n");
        return NULL;
    }
    queueHandle->msgPool.size = queueLength;
    memset(queueHandle->msgPool.pPool, 0, queueLength * msgSize + queueLength);
    queueHandle->listPool.pPool = malloc(queueLength * sizeof(Msg_t) + queueLength);
    if(!queueHandle->listPool.pPool){
        printf("queue list pool create failed!\n");
        return NULL;
    }
    queueHandle->listPool.size = queueLength;
    memset(queueHandle->listPool.pPool, 0, queueLength * sizeof(Msg_t) + queueLength);
    queueHandle->msgListHead = NULL;
    queueHandle->msgListTail = NULL;

    return queueHandle;
}

void *allocItemFromPool(Pool_t pool, int msgsize){
    int i = 0;
    void *pret = NULL;
    while(i < pool.size){
        char *pIdex = pool.pPool;
        if(pIdex[i] == 0){                      
            pIdex[i] = 1;
            break; 
        }
        ++i;
    }
    if(i == pool.size){
        pret = NULL;
    }else{
        pret = pool.pPool + pool.size + i * msgsize; 
    }
    
    return pret;
}

void freeItem(Pool_t pool, void *p, int msgSize){
    int i = 0;
    void *pret = NULL;
    char *pStart = pool.pPool + pool.size;
    char *pIdex = pool.pPool;
    while(i < pool.size){        
        if(pStart == p){    
            pIdex[i] = 0;
            break; 
        }
        pStart += msgSize;
        ++i;
    }
    if(i == pool.size){
        printf("free item failed");
    }
}

int sendMsgQueue(QueueHandle_t handle, const void *pMsg){
    void *p = allocItemFromPool(handle->msgPool, handle->msgSize);
    if(!p){
        printf("message pool is full!\n");
        return 0;
    }
    memcpy(p, pMsg, handle->msgSize);
    Msg_t *newNode = (Msg_t *)allocItemFromPool(handle->listPool, sizeof(Msg_t));
    if(!newNode){
        printf("list pool is full!\n");
        return 0;
    }
    newNode->pMsg = p;
    newNode->next = NULL;
    Msg_t *pTemp = handle->msgListHead;
    if(!pTemp){
        handle->msgListHead = newNode;
    }else{
        handle->msgListTail->next = newNode;
    }
    handle->msgListTail = newNode;
    handle->curLen++;

    return handle->msgSize;
}

void *receiveMsgQueue(QueueHandle_t handle){
    if(!handle->msgListHead){
        printf("queue is empty!\n");
        return NULL;
    }
    Msg_t *pNode = handle->msgListHead;
    handle->msgListHead = handle->msgListHead->next;
    freeItem(handle->listPool, pNode, sizeof(Msg_t));
    freeItem(handle->msgPool, pNode->pMsg, handle->msgSize);
    handle->curLen--;
    return pNode->pMsg;
}

int main(void){
    int msg[10] = {0,1,2,3,4,5,6,7,8,9};
    int *pmsg;
    QueueHandle_t mq = createMsgQueue("hellomq", 10, sizeof(int));
    if(mq){
        sendMsgQueue(mq, &msg[0]); 
        sendMsgQueue(mq, &msg[1]); 
        sendMsgQueue(mq, &msg[2]); 
        sendMsgQueue(mq, &msg[3]);
        sendMsgQueue(mq, &msg[4]);
        sendMsgQueue(mq, &msg[5]);
        sendMsgQueue(mq, &msg[6]);
        sendMsgQueue(mq, &msg[7]);
        sendMsgQueue(mq, &msg[8]);
        sendMsgQueue(mq, &msg[9]);
    }
    pmsg = receiveMsgQueue(mq);
    if(pmsg)  printf("%d\n", *pmsg);
    printf("mq curlen = %d\n", mq->curLen);
    pmsg = receiveMsgQueue(mq);
    if(pmsg)  printf("%d\n", *pmsg);
    printf("mq curlen = %d\n", mq->curLen);
    pmsg = receiveMsgQueue(mq);
    if(pmsg)  printf("%d\n", *pmsg);
    printf("mq curlen = %d\n", mq->curLen);
    pmsg = receiveMsgQueue(mq);
    if(pmsg) printf("%d\n", *pmsg);
    printf("mq curlen = %d\n", mq->curLen);
    sendMsgQueue(mq, &msg[3]); 
    pmsg = receiveMsgQueue(mq);
    if(pmsg) printf("%d\n", *pmsg);
    printf("mq curlen = %d\n", mq->curLen);

    return 0;
}

